import json
import re
import uuid
import os

def NonMotorVehicles_convert_annotations_with_choices(input_file, output_file):
    """
    将原始JSON中的检测框坐标和属性值转换为归一化比例并输出到文件
    每个属性值单独输出一行
    """
    # 加载JSON数据
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有非机动车数据
    if "NonMotorVehicles" not in data["Result"] or not data["Result"]["NonMotorVehicles"]:
        return  # 没有非机动车数据，直接退出函数
    
    # 提取非机动车数据
    non_motor_vehicles = data["Result"]["NonMotorVehicles"]
    
    with open(output_file, "a") as out_f:
        # 处理每辆非机动车
        for vehicle in non_motor_vehicles:
            box = vehicle["Img"]["DetectedBox"]
            
            # 计算归一化坐标
            x_norm = box["X"] / img_width
            y_norm = box["Y"] / img_height
            width_norm = box["Width"] / img_width
            height_norm = box["Height"] / img_height
            
            # 基础坐标字符串（添加原始宽高信息）
            base_line = (
                f"image_width:{img_width}|"
                f"image_height:{img_height}|"
                f"x:{x_norm}|"
                f"y:{y_norm}|"
                f"width:{width_norm}|"
                f"height:{height_norm}|"
            )
            
            # 写入边界框行
            bbox_line = base_line + "rectanglelabels:NonMotorVehicles|from_name:NonMotorVehiclesbbox"
            out_f.write(bbox_line + "\n")
            
            # 处理属性值数据
            if "Attributes" in vehicle and vehicle["Attributes"]:
                for attr in vehicle["Attributes"]:
                    # 只提取ValueString属性值
                    if "ValueString" in attr and attr["ValueString"]:
                        value = attr["ValueString"]
                        # 为每个属性值单独创建一行
                        line = base_line
                        if attr["AttributeName"] == "车型":
                            line += f"choices:{value}|from_name:myobject"
                        elif attr["AttributeName"] == "车身颜色":
                            line += f"choices:{value}|from_name:myobject"
                        elif attr["AttributeName"] == "车辆角度":
                            line += f"choices:{value}|from_name:myobject"
                        else:
                            # 处理其他属性
                            line += f"choices:{value}|from_name:myobject"
                        
                        out_f.write(line + "\n")

def Pedestrian_convert_annotations(input_file, output_file):
    """
    转换行人数据：边界框+性别/年龄/年龄分类属性
    """
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有行人数据
    if "Pedestrian" not in data["Result"] or not data["Result"]["Pedestrian"]:
        return  # 没有行人数据，直接退出函数
    
    # 提取行人数据
    pedestrians = data["Result"]["Pedestrian"]
    
    with open(output_file, "a") as out_f:
        # 处理每个行人
        for ped in pedestrians:
            box = ped["Img"]["DetectedBox"]
            
            # 计算归一化坐标
            x_norm = box["X"] / img_width
            y_norm = box["Y"] / img_height
            width_norm = box["Width"] / img_width
            height_norm = box["Height"] / img_height
            
            # 基础坐标字符串（添加原始宽高信息）
            base_line = (
                f"image_width:{img_width}|"
                f"image_height:{img_height}|"
                f"x:{x_norm}|"
                f"y:{y_norm}|"
                f"width:{width_norm}|"
                f"height:{height_norm}|"
            )
            
            # 写入边界框行
            bbox_line = base_line + "rectanglelabels:Pedestrian|from_name:Pedestrianbox"
            out_f.write(bbox_line + "\n")
            
            # 处理性别属性
            if "PedesAttr" in ped and "Sex" in ped["PedesAttr"] and "Name" in ped["PedesAttr"]["Sex"]:
                sex = ped["PedesAttr"]["Sex"]["Name"]
                sex_line = base_line + f"choices:{sex}|from_name:myobject"
                out_f.write(sex_line + "\n")
            
            # 处理年龄属性
            if "PedesAttr" in ped and "Age" in ped["PedesAttr"] and "Name" in ped["PedesAttr"]["Age"]:
                age = ped["PedesAttr"]["Age"]["Name"]
                age_line = base_line + f"choices:{age}|from_name:myobject"
                out_f.write(age_line + "\n")
            
            # 处理年龄分类属性（可能有多个值）
            if "PedesAttr" in ped and "Category" in ped["PedesAttr"] and ped["PedesAttr"]["Category"]:
                for category in ped["PedesAttr"]["Category"]:
                    if "Items" in category and category["Items"]:
                        for item in category["Items"]:
                            if "Name" in item:
                                category_line = base_line + f"choices:{item['Name']}|from_name:myobject"
                                out_f.write(category_line + "\n")

def PedestrianFace_convert_annotations(input_file, output_file):
    """
    转换行人人脸属性数据：边界框+人脸属性
    """
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有行人数据
    if "Pedestrian" not in data["Result"] or not data["Result"]["Pedestrian"]:
        return  # 没有行人数据，直接退出函数
    
    # 提取行人数据
    pedestrians = data["Result"]["Pedestrian"]
    
    # 属性映射表（保留用于其他逻辑）
    attribute_mapping = {
        "帽子": "PedestrianFacehat",
        "年龄": "PedestrianFaceage",
        "性别": "PedestrianFacesex",
        "口罩": "PedestrianFacemask",
        "安全帽": "PedestrianFacesafetyhat",
        "眼镜": "PedestrianFaceclass",
        "其他": "PedestrianFaceother"
    }
    
    with open(output_file, "a") as out_f:
        # 处理每个行人
        for ped in pedestrians:
            # 只处理有脸部的行人
            if "Face" not in ped or not ped["Face"]:
                continue
                
            # 获取人脸框
            face_box = ped["Face"]["Img"]["DetectedBox"]
            
            # 计算归一化坐标
            x_norm = face_box["X"] / img_width
            y_norm = face_box["Y"] / img_height
            width_norm = face_box["Width"] / img_width
            height_norm = face_box["Height"] / img_height
            
            # 基础坐标字符串（添加原始宽高信息）
            base_line = (
                f"image_width:{img_width}|"
                f"image_height:{img_height}|"
                f"x:{x_norm}|"
                f"y:{y_norm}|"
                f"width:{width_norm}|"
                f"height:{height_norm}|"
            )
            
            # 写入人脸边界框行
            bbox_line = base_line + "rectanglelabels:PedestrianFace|from_name:PedestrianFacebox"
            out_f.write(bbox_line + "\n")
            
            # 处理人脸属性
            if "Attributes" in ped["Face"] and ped["Face"]["Attributes"]:
                for attr in ped["Face"]["Attributes"]:
                    # 获取属性名称和值
                    attr_name = attr.get("Name", "")
                    attr_value = attr.get("ValueString", "")
                    
                    # 检查是否在映射表中
                    if attr_name in attribute_mapping and attr_value:
                        # 构建属性行（使用固定from_name）
                        attr_line = base_line + (
                            f"choices:{attr_value}|"
                            f"from_name:myobject"
                        )
                        out_f.write(attr_line + "\n")

def NonMotorVehiclesPassengersFace_convert_annotations(input_file, output_file):
    """
    转换非机动车乘客人脸数据：边界框+人脸属性
    """
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有非机动车数据
    if "NonMotorVehicles" not in data["Result"] or not data["Result"]["NonMotorVehicles"]:
        return  # 没有非机动车数据，直接退出函数
    
    # 属性映射表（保留用于其他逻辑）
    attribute_mapping = {
        "帽子": "NonMotorVehiclesPassengersFacehat",
        "年龄": "NonMotorVehiclesPassengersFaceage",
        "性别": "NonMotorVehiclesPassengersFacesex",
        "口罩": "NonMotorVehiclesPassengersFacemask",
        "安全帽": "NonMotorVehiclesPassengersFacesafetyhat",
        "眼镜": "NonMotorVehiclesPassengersFaceclass",
        "其他": "NonMotorVehiclesPassengersFaceother"
    }
    
    with open(output_file, "a") as out_f:
        # 遍历所有非机动车
        for vehicle in data["Result"]["NonMotorVehicles"]:
            # 检查是否有乘客
            if "Passengers" not in vehicle or not vehicle["Passengers"]:
                continue
                    
            # 遍历每位乘客
            for passenger in vehicle["Passengers"]:
                # 检查是否有Face属性
                if "Face" not in passenger or not passenger["Face"]:
                    continue
                    
                # 获取人脸框
                face_box = passenger["Face"]["Img"]["DetectedBox"]
                
                # 计算归一化坐标
                x_norm = face_box["X"] / img_width
                y_norm = face_box["Y"] / img_height
                width_norm = face_box["Width"] / img_width
                height_norm = face_box["Height"] / img_height
                
                # 基础坐标字符串（添加原始宽高信息）
                base_line = (
                    f"image_width:{img_width}|"
                    f"image_height:{img_height}|"
                    f"x:{x_norm}|"
                    f"y:{y_norm}|"
                    f"width:{width_norm}|"
                    f"height:{height_norm}|"
                )
                
                # 写入乘客人脸边界框行
                bbox_line = base_line + "rectanglelabels:NonMotorVehiclesPassengers|from_name:NonMotorVehiclesPassengersbox"
                out_f.write(bbox_line + "\n")
                
                # 处理人脸属性
                if "Attributes" in passenger["Face"] and passenger["Face"]["Attributes"]:
                    for attr in passenger["Face"]["Attributes"]:
                        # 获取属性名称和值
                        attr_name = attr.get("Name", "")
                        attr_value = attr.get("ValueString", "")
                        
                        # 检查是否在映射表中
                        if attr_name in attribute_mapping and attr_value:
                            # 构建属性行（使用固定from_name）
                            attr_line = base_line + (
                                f"choices:{attr_value}|"
                                f"from_name:myobject"
                            )
                            out_f.write(attr_line + "\n")

def NonMotorVehiclesPassengersAttributes_convert_annotations(input_file, output_file):
    """
    转换非机动车乘客属性数据：边界框+乘客属性
    """
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有非机动车数据
    if "NonMotorVehicles" not in data["Result"] or not data["Result"]["NonMotorVehicles"]:
        return  # 没有非机动车数据，直接退出函数
    
    # 属性映射表（保留用于其他逻辑）
    attribute_mapping = {
        "上衣颜色": "NonMotorVehiclesPassengersAttributesupper_color",
        "上衣样式": "NonMotorVehiclesPassengersAttributesupper_style",
        "性别": "NonMotorVehiclesPassengersAttributessex",
        "头部标志物": "NonMotorVehiclesPassengersAttributesheadmarker",
        "其他": "NonMotorVehiclesPassengersAttributesother"
    }
    
    with open(output_file, "a") as out_f:
        # 遍历所有非机动车
        for vehicle in data["Result"]["NonMotorVehicles"]:
            # 检查是否有乘客
            if "Passengers" not in vehicle or not vehicle["Passengers"]:
                continue
                    
            # 遍历每位乘客
            for passenger in vehicle["Passengers"]:
                # 获取乘客框（使用DetectedBox）
                if "Img" in passenger and "DetectedBox" in passenger["Img"]:
                    box = passenger["Img"]["DetectedBox"]
                else:
                    continue
                
                # 计算归一化坐标
                x_norm = box["X"] / img_width
                y_norm = box["Y"] / img_height
                width_norm = box["Width"] / img_width
                height_norm = box["Height"] / img_height
                
                # 基础坐标字符串（添加原始宽高信息）
                base_line = (
                    f"image_width:{img_width}|"
                    f"image_height:{img_height}|"
                    f"x:{x_norm}|"
                    f"y:{y_norm}|"
                    f"width:{width_norm}|"
                    f"height:{height_norm}|"
                )
                
                # 写入乘客边界框行
                bbox_line = base_line + "rectanglelabels:NonMotorVehiclesPassengersAttributes|from_name:NonMotorVehiclesPassengersAttributesbox"
                out_f.write(bbox_line + "\n")
                
                # 处理乘客属性
                if "Attributes" in passenger and passenger["Attributes"]:
                    for attr in passenger["Attributes"]:
                        # 获取属性名称和值
                        attr_name = attr.get("AttributeName", "")
                        value_string = attr.get("ValueString", "")
                        
                        # 检查是否在映射表中
                        if attr_name in attribute_mapping and value_string:
                            # 构建属性行（使用固定from_name）
                            attr_line = base_line + (
                                f"choices:{value_string}|"
                                f"from_name:myobject"
                            )
                            out_f.write(attr_line + "\n")

def FacesAttributes_convert_annotations(input_file, output_file):
    """
    转换独立人脸数据：边界框+人脸属性
    """
    with open(input_file) as f:
        data = json.load(f)
    
    # 获取图像尺寸
    img_width = data["Result"]["Image"]["Data"]["Width"]
    img_height = data["Result"]["Image"]["Data"]["Height"]
    
    # 检查是否有独立人脸数据
    if "Faces" not in data["Result"] or not data["Result"]["Faces"]:
        return  # 没有独立人脸数据，直接退出函数
    
    # 属性映射表（保留用于其他逻辑）
    attribute_mapping = {
        "年龄": "FaceAttributesage",
        "性别": "FaceAttributessex",
        "帽子": "FaceAttributeshat",
        "口罩": "FaceAttributesmask",
        "眼镜": "FaceAttributesclass",
        "安全帽": "FaceAttributessafetyhat",
        "其他": "FaceAttributesother"
    }
    
    with open(output_file, "a") as out_f:
        # 遍历所有独立人脸
        for face in data["Result"]["Faces"]:
            #获取人脸框
            face_box = face["Img"]["DetectedBox"]
            
            # 计算归一化坐标
            x_norm = face_box["X"] / img_width
            y_norm = face_box["Y"] / img_height
            width_norm = face_box["Width"] / img_width
            height_norm = face_box["Height"] / img_height
            
            # 基础坐标字符串（添加原始宽高信息）
            base_line = (
                f"image_width:{img_width}|"
                f"image_height:{img_height}|"
                f"x:{x_norm}|"
                f"y:{y_norm}|"
                f"width:{width_norm}|"
                f"height:{height_norm}|"
            )
            
            # 写入人脸边界框行
            bbox_line = base_line + "rectanglelabels:Face|from_name:Facebox"
            out_f.write(bbox_line + "\n")
            
            # 处理人脸属性
            if "Attributes" in face and face["Attributes"]:
                for attr in face["Attributes"]:
                    # 获取属性名称和值
                    attr_name = attr.get("Name", "")
                    attr_value = attr.get("ValueString", "")
                    
                    # 检查是否在映射表中
                    if attr_name in attribute_mapping and attr_value:
                        # 构建属性行（使用固定from_name）
                        attr_line = base_line + (
                            f"choices:{attr_value}|"
                            f"from_name:myobject"
                        )
                        out_f.write(attr_line + "\n")
def parse_line(line):
    """解析单行数据，返回字典"""
    parts = line.strip().split('|')
    data = {}
    for part in parts:
        if ':' in part:
            key, value = part.split(':', 1)
            data[key] = value
    return data

def convert_file_to_json(input_file_path, output_file_path):
    """从文件读取数据并转换为JSON格式"""
    # 读取输入文件
    with open(input_file_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
    
    # 存储所有结果
    result_list = []
    
    # 存储每个对象的分组ID
    group_ids = {}
    
    # 处理每一行
    for line in lines:
        # 跳过空行
        if not line.strip():
            continue
            
        data = parse_line(line)
        
        # 准备结果项
        item = {
            "original_width": int(data.get("image_width", 0)),
            "original_height": int(data.get("image_height", 0)),
            "image_rotation": 0,
            "value": {
                "x": float(data.get("x", 0)) * 100,
                "y": float(data.get("y", 0)) * 100,
                "width": float(data.get("width", 0)) * 100,
                "height": float(data.get("height", 0)) * 100,
                "rotation": 0
            },
            "to_name": "image",
            "origin": "manual"
        }
        
        # 生成或获取分组ID
        coord_key = f"{data.get('x')}_{data.get('y')}_{data.get('width')}_{data.get('height')}"
        if coord_key not in group_ids:
            group_ids[coord_key] = str(uuid.uuid4())[:10]  # 使用简短的UUID
        item["id"] = group_ids[coord_key]
        
        # 处理矩形标签
        if "rectanglelabels" in data:
            item["type"] = "rectanglelabels"
            item["from_name"] = data.get("from_name", "")
            item["value"]["rectanglelabels"] = [data["rectanglelabels"]]
            result_list.append(item)
        
        # 处理选择项
        elif "choices" in data:
            item["type"] = "choices"
            item["from_name"] = data.get("from_name", "myobject")
            item["value"]["choices"] = [data["choices"]]
            result_list.append(item)
    
    # 创建完整的JSON结构
    result_json = {"result": result_list}
    
    # 保存到输出文件
    
    return result_json
def get_data():
    """
    返回一个固定的数据结构。
    """
    return '[{"id":32,"annotations":[{"id":15,"completed_by":1,'

def generate_task_string(image_path: str) -> str:
    """
    根据输入的图片路径，生成并返回一个特定格式的字符串。
 
    Args:
        image_path: 原始图片路径，例如 "/data/upload/7/example.jpg"。
 
    Returns:
        一个符合特定格式的字符串，其中路径中的 "/" 被替换为 "\/"。
    """
    # 将输入路径中的 '/' 替换为 '\/'
    # 在Python字符串中，要表示一个字面上的反斜杠'\'，需要使用'\\'
    escaped_image_path = image_path.replace('/', '\\/')
 
    # 修正f-string语法：所有字面上的'{'或'}'都必须写成'{{'或'}}'
    result_string = (
        f',"was_cancelled":false,"ground_truth":false,"created_at":"2025-11-03T02:07:45.347226Z",'
        f'"updated_at":"2025-11-03T02:07:45.347260Z","draft_created_at":"2025-11-03T02:07:34.040431Z",'
        f'"lead_time":19.533,"prediction":{{}},"result_count":0,'  # {} -> {{}}
        f'"unique_id":"bedc640a-3298-472a-870b-187d6797995d","import_id":null,"last_action":null,'
        f'"task":32,"project":7,"updated_by":1,"parent_prediction":null,"parent_annotation":null,'
        f'"last_created_by":null}}],"file_upload":"6892f699-keyframe_0001.jpg","drafts":[],"predictions":[],'  # } -> }}
        f'"data":{{"image":"{escaped_image_path}"}},"meta":{{}},"created_at":"2025-11-03T02:07:16.272243Z",'  # {} 和 meta:{} -> {{}}
        f'"updated_at":"2025-11-03T02:07:45.405358Z","inner_id":1,"total_annotations":1,"cancelled_annotations":0,'
        f'"total_predictions":0,"comment_count":0,"unresolved_comment_count":0,"last_comment_updated_at":null,'
        f'"project":7,"updated_by":1,"comment_authors":[]}}]'  # 修正：末尾的 } -> }}
    )
    return result_string

def remove_first_and_last(input_string):
    """Removes the first and last character from a string."""
    return input_string[1:-1]
# 使用示例
def json_to_lab(json_name,new_json_name,pic_name):   
    # 输入和输出文件名
    input_json = json_name 
    output_txt = "test.label.txt"
    
    # 清空输出文件
    open(output_txt, 'w').close()
    
    # 执行转换
    NonMotorVehicles_convert_annotations_with_choices(input_json, output_txt)
    Pedestrian_convert_annotations(input_json, output_txt)
    PedestrianFace_convert_annotations(input_json, output_txt)
    NonMotorVehiclesPassengersFace_convert_annotations(input_json, output_txt)
    NonMotorVehiclesPassengersAttributes_convert_annotations(input_json, output_txt)
    FacesAttributes_convert_annotations(input_json, output_txt)
    
    print(f"转换完成！结果已保存到 {output_txt}")
    input_file = "test.label.txt"  # 替换为您的输入文件路径
    output_file = new_json_name    # 输出JSON文件路径
    pic_file = pic_name
        # 检查输入文件是否存在
    if not os.path.exists(input_file):
        print(f"错误: 输入文件 '{input_file}' 不存在!")
        exit(1)
    
    # 执行转换
    result_json = convert_file_to_json(input_file, output_file)
    start_data = get_data()     
    end_data = generate_task_string(pic_file)
    data_json = start_data+remove_first_and_last(json.dumps(result_json, ensure_ascii=False, indent=2))+end_data
    with open(output_file, 'w', encoding='utf-8') as f:
     f.write(data_json)
 
    print(f"转换完成！结果已保存到 {output_file}")
    print(f"共转换了 {len(result_json['result'])} 条记录")
    print("程序执行完毕")

if __name__ == "__main__":

       with open("list", 'r') as file:
        for line in file:
            # 移除行尾的换行符和空格
            line = line.strip()
            # 跳过空行
            if not line:
                continue
            # 使用'|'分割行
            parts = line.split('|')
            # 确保分割后有足够的元素
            if len(parts) >= 3:
                # 提取第一部分（JSON文件名）和第二部分（图片路径）
                json_file = parts[0].strip()
                image_path = parts[1].strip()
                # 按指定格式打印
                print(f"{json_file}    {image_path}")
                json_to_lab(json_file,"imp_"+json_file,image_path)
  
    
